package com.hontech.desktoppastacooker.ui.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import androidx.fragment.app.Fragment
import com.hontech.desktoppastacooker.R
import com.hontech.desktoppastacooker.conn.Proto
import com.hontech.desktoppastacooker.conn.SerialPortMod
import com.hontech.desktoppastacooker.conn.serial.Uint8
import com.hontech.desktoppastacooker.device.Device
import com.hontech.desktoppastacooker.device.Rfid
import com.hontech.desktoppastacooker.device.RfidEvent
import com.hontech.desktoppastacooker.ui.window.showProg
import com.hontech.desktoppastacooker.utils.*
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.delay
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeoutException

class CookingFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_cooking, null)
        CookingDelegate(view)
        return view
    }

}

private class CookingDelegate(view: View) {

    private val etC = view.findViewById<EditText>(R.id.id_cooking_et_c)
    private val etDrainColdWater = view.findViewById<EditText>(R.id.id_cooking_et_drain_cold_water)
    private val etD = view.findViewById<EditText>(R.id.id_cooking_et_d)
    private val etSteamDuration = view.findViewById<EditText>(R.id.id_cooking_et_steam_duration)
    private val btnClean = view.findViewById<Button>(R.id.id_cooking_btn_clean)

    private val etK = view.findViewById<EditText>(R.id.id_cooking_et_k)
    private val etPreWater = view.findViewById<EditText>(R.id.id_cooking_et_pre_water)
    private val etF = view.findViewById<EditText>(R.id.id_cooking_et_f)
    private val etG = view.findViewById<EditText>(R.id.id_cooking_et_g)
    private val etDefroze = view.findViewById<EditText>(R.id.id_cooking_et_defroze)
    private val etE = view.findViewById<EditText>(R.id.id_cooking_et_e)
    private val etPourWater = view.findViewById<EditText>(R.id.id_cooking_et_pour_water)
    private val etH = view.findViewById<EditText>(R.id.id_cooking_et_h)
    private val etMixSoup = view.findViewById<EditText>(R.id.id_cooking_et_mix_soup)
    private val etI = view.findViewById<EditText>(R.id.id_cooking_et_i)
    private val etClogging = view.findViewById<EditText>(R.id.id_cooking_et_clogging)
    private val btnCooking = view.findViewById<Button>(R.id.id_cooking_btn_cooking)
    private val btnStart = view.findViewById<Button>(R.id.id_cooking_btn_start_cooking)

    private class CleanOption(
        val c: Int,
        val drainColdWater: Int,
        val d: Int,
        val steamDuration: Int
    )

    private class CookingOption(
        val k: Int,
        val preWater: Int,
        val f: Int,
        val g: Int,
        val defroze: Int,
        val e: Int,
        val pourWater: Int,
        val h: Int,
        val mixSoup: Int,
        val i: Int,
        val clogging: Int
    )

    private fun getCookingOption(): CookingOption {
        return CookingOption(
            etK.toInt(),
            etPreWater.toInt(),
            etF.toInt(),
            etG.toInt(),
            etDefroze.toInt(),
            etE.toInt(),
            etPourWater.toInt(),
            etH.toInt(),
            etMixSoup.toInt(),
            etI.toInt(),
            etClogging.toInt()
        )
    }

    private fun getCleanOption(): CleanOption {
        return CleanOption(
            etC.toInt(),
            etDrainColdWater.toInt(),
            etD.toInt(),
            etSteamDuration.toInt()
        )
    }

    init {

        btnCooking.onClick {

            try {

                val option = getCookingOption()

                wrapReq("煮面", "",
                    600 * 1000,
                    Proto.REQ_COOKING,
                    arrayOf(
                        Uint8(option.k),
                        Uint8(option.preWater),
                        Uint8(option.f),
                        Uint8(option.g),
                        Uint8(option.defroze),
                        Uint8(option.e),
                        Uint8(option.pourWater),
                        Uint8(option.h),
                        Uint8(option.mixSoup),
                        Uint8(option.i),
                        Uint8(option.clogging)
                    )
                )

            } catch (e: Exception) {
                e.printStackTrace()
            }

        }

        btnClean.onClick {

            try {

                val clean = getCleanOption()

                wrapReq("清洗", "", 60 * 1000,
                    Proto.REQ_CLEAN,
                    arrayOf(
                        Uint8(clean.c),
                        Uint8(clean.drainColdWater),
                        Uint8(clean.d),
                        Uint8(clean.steamDuration)
                    )
                )

            } catch (e: Exception) {
                e.printStackTrace()
            }

        }

        btnStart.onClick(::cookingStart)
    }

    private var startFlag = false
    private var rfidFuture: CompletableDeferred<Rfid>? = null

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onRfidEvent(env: RfidEvent) {
        rfidFuture?.complete(env.rfid)
    }

    private suspend fun waitNear(flag: Boolean) {
        var count = 0
        while ( Device.status.isNear() == flag ) {
            delay(500)
            count += 500
            if (count >= 30 * 1000) {
                throw TimeoutException("等待放碗超时")
            }
        }
        delay(800)
    }

    private suspend fun cookingStart() {

        if (startFlag) {
            return
        }
        startFlag = true

        rfidFuture = CompletableDeferred()
        eventBus.register(this)

        val dialog = showProg("启动煮面流程", "等待检测到RFID")

        try {

            val rfid = rfidFuture!!.await(30 * 1000)
            dialog.setMsg("检测到条码:${rfid.epc} 请放碗")

            SerialPortMod.request(
                30 * 1000,
                Proto.REQ_DOOR_CTRL,
                arrayOf(Uint8(0))
            ).assertErr()

            waitNear(false) // 没有碗则等待
            dialog.setMsg("开始煮面")
            val option = getCookingOption()

            SerialPortMod.request(
                600 * 1000,
                Proto.REQ_COOKING,
                arrayOf(
                    Uint8(option.k),
                    Uint8(option.preWater),
                    Uint8(option.f),
                    Uint8(option.g),
                    Uint8(option.defroze),
                    Uint8(option.e),
                    Uint8(option.pourWater),
                    Uint8(option.h),
                    Uint8(option.mixSoup),
                    Uint8(option.i),
                    Uint8(option.clogging)
                )
            ).assertErr()

            dialog.setMsg("煮面成功 请拿碗")
            waitNear(true) // 有碗则等待
            dialog.setMsg("关门")

            SerialPortMod.request(
                30 * 1000,
                Proto.REQ_DOOR_CTRL,
                arrayOf(Uint8(1))
            ).assertErr()

            dialog.success("煮面流程结束")

        } catch (e: Exception) {
            e.printStackTrace()
            dialog.error(e)
        } finally {
            startFlag = false
            eventBus.unregister(this)
        }

    }

}












